home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
WD_SRC.ZIP
/
SOURCE
/
DRAW.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-12
|
26KB
|
963 lines
#include "..\Source\LastWolf.hpp"
// What the fixed-point numbers are shifted by (as extra precision) for the VLine routines.
#define TEXTURE_FIX 5
#define CLIP_Z FIX(2)
#define MAX_X_CLIPS 200
// A lookup table for the parallaxing sky.
MDWordArray parallaxLookup;
// Top and bottom Y for all the Lines.
Fixed topY = FIX(-84);
Fixed bottomY = FIX(36);
// Used when projecting coordinates.
WORD centerX = 160;
WORD centerY = 100;
// The transformation stuff.
Fixed playerAngleSine, playerAngleCosine;
Fixed translateX, translateY;
Angle transAngle;
// What you scale the world by horizontally .. xViewSlope and xViewSlopeAngle depend on it!
WORD xWorldScale=160;
// World Y scale.
WORD yWorldScale;
// The slope of the viewing angle ... used to cut off excess lines.
// Equation to get slope = (screenMaxX / xWorldScale)
// NOTE: This is an x/y slope, because x has the possibility of being zero.
// Also, screenMaxX = half the screen (160).
Fixed xViewSlope = (Fixed)(1.0F * 16384.0F);
// xViewSlopeAngle = atan( 1/xViewSlope ).
Angle xViewAngle = 128;
// Variables for the screen X clipping table.
X_Clip clipSpace[MAX_X_CLIPS];
WORD nClipsUsed;
X_Clip headNode, tailNode;
void dr_InitTables()
{
Angle i;
float ArcTangent, ArcCosine;
// Fill in SIN_TABLE[].
for( i=0; i < ANGLE_RES; i++ )
SIN_TABLE[i] = (Fixed)(sin(((float)i * 6.28) / ANGLE_RES) * FIXED_ONE);
// Fill in ATAN_TABLE[].
for( i=0; i < ANGLE_RES; i++ )
{
ArcTangent = atan((float)i / (float)ANGLE_RES);
ATAN_TABLE[i] = (Angle)((ArcTangent * (float)ANGLE_RES) / 6.28F);
}
// Fill in ACOS_TABLE[].
for( i=0; i < ANGLE_RES; i++ )
{
ArcCosine = acos( (float)i / (float)ANGLE_RES );
ACOS_TABLE[i] = (ArcCosine * FIXED_ONE);
}
// Set up the X_Clip stuff.
headNode.pNext = &tailNode;
tailNode.pNext = &tailNode;
}
void dr_GenerateLookups()
{
Fixed parallaxX;
DWORD x;
Texture *pSky;
// Generate the parallaxing sky lookup table.
pSky = tx_GetTexture( curLevel.idCurSky );
parallaxLookup.SetSize( s_DrawWidth );
for( x=s_MinX; x < s_MaxX; x++ )
{
parallaxX = FIXED_ONE - (FIX( (x-s_MinX)-(s_DrawWidth/2) ) / ((s_DrawWidth*2) / 3));
parallaxX = SIN_TABLE[ (parallaxX >> (FIXED_SHIFT-8)) + 255 ];
parallaxX = parallaxX >> pSky->xTextureShift;
parallaxLookup.Set( x-s_MinX, parallaxX );
}
}
void dr_DrawScreen()
{
// Setup misc. variables.
nClipsUsed = 0;
headNode.x = s_MinX;
headNode.pNext = &tailNode;
tailNode.x = s_MaxX;
tailNode.pNext = &tailNode;
// Re-computer all the viewing parameters.
centerX = s_MinX + ((s_MaxX - s_MinX)/2);
centerY = s_MinY + ((s_MaxY - s_MinY)/2);
yWorldScale = s_DrawHeight / 2;
xWorldScale = s_DrawWidth / 2;
xViewSlope = FIX(centerX) / (s_DrawWidth/2);
dr_SetupTransformation(&player);
bsp_TraverseAndDrawTree(curLevel.pRootLine);
return;
}
void dr_SetupTransformation( Player *pPlayer )
{
playerAngleSine = SAFE_SIN(pPlayer->facingAngle);
playerAngleCosine = SAFE_COS(pPlayer->facingAngle);
transAngle = (pPlayer->facingAngle - PI) & ANGLE_MASK;
translateX = -pPlayer->xPos;
translateY = -pPlayer->yPos;
}
DrawReturn dr_DrawWall( CLine *pWall, SideDir viewSide )
{
ProcessWall Wall;
Wall.pLine = pWall;
Wall.pPlayer = &player;
Wall.viewSide = viewSide;
Wall.bTextureInitted = FALSE;
// Get the wall into the player's viewspace to project it.
if( !dr_TransformWall( &Wall ) )
return WallOffScreen;
// Clip it against the y=CLIP_Z Line.
if( !dr_ClipWall( &Wall ) )
return WallOffScreen;
// Project it to get all the screen coordinates.
if( !dr_ProjectWall( &Wall ) )
return WallOffScreen;
// Clip the wall's x coordinates against the current clip stuff.
return dr_TableClipAndDrawWall( &Wall );
}
SideDir dr_PruneTree( CLine *pLine )
{
// Check if the wall is off AND it doesn't touch the viewing angles, in which case it has
// a whole invisible subtree.
// TEMPORARY: Return intercept until this routine is implemented.
pLine=pLine;
return Intersect;
}
BOOL dr_TransformWall( ProcessWall *pWall )
{
WORD localX1, localY1, localX2, localY2;
WORD texOriginX, texOriginY, texHorzX, texHorzY;
// Rotate the Line's coordinates.
localX1 = pWall->pLine->pPoint1->localX + translateX;
localY1 = pWall->pLine->pPoint1->localY + translateY;
localX2 = pWall->pLine->pPoint2->localX + translateX;
localY2 = pWall->pLine->pPoint2->localY + translateY;
pWall->x1 = ((localX1 * playerAngleCosine) - (localY1 * playerAngleSine));
pWall->y1 = ((localX1 * playerAngleSine) + (localY1 * playerAngleCosine));
pWall->x2 = ((localX2 * playerAngleCosine) - (localY2 * playerAngleSine));
pWall->y2 = ((localX2 * playerAngleSine) + (localY2 * playerAngleCosine));
pWall->normalX = FMul(pWall->pLine->A, playerAngleCosine) - FMul(pWall->pLine->B, playerAngleSine) + translateX;
pWall->normalY = FMul(pWall->pLine->A, playerAngleSine) + FMul(pWall->pLine->B, playerAngleCosine) + translateY;
// Fill in texture mapping stuff.
texOriginX = pWall->pLine->texOriginX + translateX;
texOriginY = pWall->pLine->texOriginY + translateY;
texHorzX = pWall->pLine->texHorzX + translateX;
texHorzY = pWall->pLine->texHorzY + translateY;
pWall->originX = ((texOriginX * playerAngleCosine) - (texOriginY * playerAngleSine));
pWall->originZ = ((texOriginX * playerAngleSine) + (texOriginY * playerAngleCosine));
pWall->horzX = ((texHorzX * playerAngleCosine) - (texHorzY * playerAngleSine));
pWall->horzZ = ((texHorzX * playerAngleSine) + (texHorzY * playerAngleCosine));
// Set which side the player is looking at and, if there's no texture there, don't draw the wall.
if( pWall->viewSide == LeftSide )
{
if( pWall->pLine->idLeftTex == BAD_TEXTURE_ID )
return FALSE;
else
pWall->viewSide = LeftSide;
}
else
{
if( pWall->pLine->idRightTex == BAD_TEXTURE_ID )
return FALSE;
else
pWall->viewSide = RightSide;
}
return TRUE;
}
BOOL dr_ClipWall( ProcessWall *pWall )
{
// Used for clipping against the view boundaries.
Fixed x1, y1, x2, y2;
Angle rotateAngle;
WORD pointClipped;
// First check if it even needs to be clipped.
if( pWall->y1 > CLIP_Z && pWall->y2 > CLIP_Z )
{
pWall->t1 = 0;
pWall->t2 = FIXED_ONE;
}
else if( pWall->y1 <= CLIP_Z && pWall->y2 <= CLIP_Z )
return FALSE;
else
{
// Clip against z=CLIP_Z.
dr_ClipAgainstLine( CLIP_Z, &pWall->x1, &pWall->y1, &pWall->x2, &pWall->y2, &pWall->t1, &pWall->t2, TRUE );
}
// Now clip the Line against the viewing angles.
// Clip against the right side.
rotateAngle = (ANGLE_RES-xViewAngle) & ANGLE_MASK;
RotatePointFixed( 0, 0, rotateAngle, pWall->x1, pWall->y1, &x1, &y1 );
RotatePointFixed( 0, 0, rotateAngle, pWall->x2, pWall->y2, &x2, &y2 );
// Check if it needs to be clipped at all.
if( y1 < 0 && y2 < 0 )
return FALSE;
else if( y1 > 0 && y2 > 0 )
;
else
{
// Clip it.
pointClipped = dr_ClipAgainstLine( 0, &x1, &y1, &x2, &y2, &pWall->t1, &pWall->t2, TRUE );
// Rotate the point that got clipped back.
rotateAngle = xViewAngle;
if( pointClipped == 1 )
RotatePointFixed( 0, 0, rotateAngle, x1, y1, &pWall->x1, &pWall->y1 );
else
RotatePointFixed( 0, 0, rotateAngle, x2, y2, &pWall->x2, &pWall->y2 );
}
// Clip against the left side (xViewAngle+HALF_PI).
rotateAngle = (ANGLE_RES - (PI-xViewAngle)) & ANGLE_MASK;
RotatePointFixed( 0, 0, rotateAngle, pWall->x1, pWall->y1, &x1, &y1 );
RotatePointFixed( 0, 0, rotateAngle, pWall->x2, pWall->y2, &x2, &y2 );
// Check if it needs to be clipped at all.
if( y1 > 0 && y2 > 0 )
return FALSE;
else if( y1 < 0 && y2 < 0 )
;
else
{
// Clip it.
pointClipped = dr_ClipAgainstLine( 0, &x1, &y1, &x2, &y2, &pWall->t1, &pWall->t2, FALSE );
// Rotate the point that got clipped back.
rotateAngle = PI-xViewAngle;
if( pointClipped == 1 )
RotatePointFixed( 0, 0, rotateAngle, x1, y1, &pWall->x1, &pWall->y1 );
else
RotatePointFixed( 0, 0, rotateAngle, x2, y2, &pWall->x2, &pWall->y2 );
}
return TRUE;
}
BOOL dr_ProjectWall( ProcessWall *pWall )
{
WORD tempX;
WORD y1Top, y2Top;
WORD y1Bottom, y2Bottom;
Fixed x1Div, x2Div, y1Div, y2Div;
BYTE drawColor;
// Keep in mind, pWall->y1 & 2 is really z1 & 2...
x1Div = pWall->y1 / xWorldScale;
x2Div = pWall->y2 / xWorldScale;
y1Div = pWall->y1 / yWorldScale;
y2Div = pWall->y2 / yWorldScale;
pWall->screenX1 = W_UNFIX( FDiv( pWall->x1, x1Div ) ) + centerX;
pWall->screenX2 = W_UNFIX( FDiv( pWall->x2, x2Div ) ) + centerX;
if( pWall->screenX1 == pWall->screenX2 )
return FALSE;
y1Top = W_UNFIX( FDiv( topY, y1Div ) ) + centerY;
y1Bottom = W_UNFIX( FDiv( bottomY, y1Div ) ) + centerY;
y2Top = W_UNFIX( FDiv( topY, y2Div ) ) + centerY;
y2Bottom = W_UNFIX( FDiv( bottomY, y2Div ) ) + centerY;
// Fill in the information for the top and bottom lines.
pWall->topSlope = FIX(y2Top - y1Top) / (pWall->screenX2 - pWall->screenX1);
pWall->bottomSlope = FIX(y2Bottom - y1Bottom) / (pWall->screenX2 - pWall->screenX1);
pWall->yTopIntercept = y1Top - W_UNFIX(pWall->screenX1 * pWall->topSlope);
pWall->yBottomIntercept = y1Bottom - W_UNFIX(pWall->screenX1 * pWall->bottomSlope);
// Make sure screenX 1 and 2 go from left to right.
if( pWall->screenX1 > pWall->screenX2 )
{
tempX = pWall->screenX1;
pWall->screenX1 = pWall->screenX2;
pWall->screenX2 = tempX;
pWall->bFlippedX = TRUE;
}
else
pWall->bFlippedX = FALSE;
// Show the projected points.
if( bDisplayProjectionPoints )
{
drawColor = 35;
if( tempX == pWall->screenX2 )
{
s_SetPixel( pWall->screenX2, y1Top, drawColor );
s_SetPixel( pWall->screenX2, y1Bottom, drawColor );
s_SetPixel( pWall->screenX1, y2Top, drawColor );
s_SetPixel( pWall->screenX1, y2Bottom, drawColor );
}
else
{
s_SetPixel( pWall->screenX1, y1Top, drawColor );
s_SetPixel( pWall->screenX1, y1Bottom, drawColor );
s_SetPixel( pWall->screenX2, y2Top, drawColor );
s_SetPixel( pWall->screenX2, y2Bottom, drawColor );
}
}
// Set the unclipped ones here.
pWall->unclippedScreenX1 = pWall->screenX1;
pWall->unclippedScreenX2 = pWall->screenX2;
return TRUE;
}
DrawReturn dr_TableClipAndDrawWall( ProcessWall *pWall )
{
X_Clip *pCurNode, *pPrevNode, *pNewNode;
BOOL bIn;
// Screen boundary clipping.
//////////////////////
// Test if it's all the way off the screen.
if( pWall->screenX2 < s_MinX )
return WallOffScreen;
if( pWall->screenX1 >= s_MaxX )
return WallOffScreen;
if( pWall->screenX1 < s_MinX )
pWall->screenX1 = s_MinX;
if( pWall->screenX2 >= s_MaxX )
pWall->screenX2 = s_MaxX;
if( pWall->screenX1 == pWall->screenX2 )
return DrewWall;
// Find where the Line enters into the table. Insert a new X_Clip in the table
// if necessary.
pCurNode = &headNode;
pPrevNode = &headNode;
bIn = FALSE;
while( pCurNode->pNext != pCurNode )
{
if( pWall->screenX1 >= pCurNode->x && pWall->screenX1 < pCurNode->pNext->x )
{
if( bIn )
{
// Doesn't matter what these are because you're not going to be drawing anything
// at screenX1.
pPrevNode = pCurNode;
break;
}
else if( (pWall->screenX1 - pCurNode->x) < 1 && pCurNode != &headNode )
{
break;
}
else
{
pNewNode = GetXClip();
pNewNode->x = pWall->screenX1;
pNewNode->pNext = pCurNode->pNext;
pCurNode->pNext = pNewNode;
pCurNode = pNewNode;
pPrevNode = pCurNode;
break;
}
}
// Advance in the list and update the in/out flag.
pPrevNode = pCurNode;
pCurNode = pCurNode->pNext;
bIn = !bIn;
}
// At this point, pPrevNode = pCurNode, and bIn is valid. Draw and remove edges until
// you hit pWall->screenX2.
while( pCurNode->pNext != pCurNode )
{
// If you're at the end of the Line...
if( pWall->screenX2 <= pCurNode->pNext->x || pCurNode->pNext == &tailNode )
{
if( !bIn )
{
if( pCurNode->pNext->x - pWall->screenX2 < 1 )
{
pPrevNode->pNext = pCurNode->pNext->pNext;
dr_DrawHorizontalStrip( pWall, pCurNode->x, pWall->screenX2 );
}
else
{
// If you're in open space, add a new edge for screenX2 and get rid of the
// current edge.
pNewNode = GetXClip();
pNewNode->x = pWall->screenX2;
pNewNode->pNext = pCurNode->pNext;
pPrevNode->pNext = pNewNode;
dr_DrawHorizontalStrip( pWall, pCurNode->x, pWall->screenX2 );
}
}
else
{
pPrevNode->pNext = pCurNode->pNext;
}
break;
}
if( !bIn )
dr_DrawHorizontalStrip( pWall, pCurNode->x, pCurNode->pNext->x );
pPrevNode->pNext = pCurNode->pNext;
pCurNode = pCurNode->pNext;
bIn = !bIn;
}
// Check if the whole screen is drawn.
if( (headNode.pNext->x == s_MinX && headNode.pNext->pNext->x == s_MaxX) || headNode.pNext->x == s_MaxX )
return ScreenCompletelyDrawn;
else
return DrewWall;
}
X_Clip *GetXClip()
{
X_Clip *pRetVal;
pRetVal = &clipSpace[nClipsUsed++];
assert(nClipsUsed < MAX_X_CLIPS);
return pRetVal;
}
void dr_DrawHorizontalStrip( ProcessWall *pWall, WORD xLeft, WORD xRight )
{
Fixed tLeft, tRight;
Fixed curTopY, curBottomY;
WORD x;
BYTE *pPaletteMap;
DWORD paletteMap;
Fixed worldXStart, worldZStart;
Fixed worldXEnd, worldZEnd;
Fixed worldXStep, worldZStep;
Fixed fixedWorldX, fixedWorldZ;
DWORD worldX, worldZ;
WORD xTexturePos=0;
Texture *pTexture, *pSky;
// Stuff for showing projection lines.
DWORD y1, y2;
BYTE color1=30, color2=130;
// Texture mapping variables.
Fixed a, c, u;
WORD unfixedTopY, unfixedBottomY;
Fixed textureStep, textureClipAdd, tempStep, texturePos;
BYTE *pParallax;
#pragma aux dr_WallLine = \
"mov eax,texturePos" \
"sub eax,textureStep" \
"LOOP_AGAIN:" \
"add eax,textureStep" \
"mov texturePos,eax" \
"shr eax,20" \
"xor edx,edx" \
"mov dl,[esi+eax]" \
"mov al, [ebx+edx]" \
"mov [edi],al" \
"mov eax,texturePos" \
"add edi,s_PagedWidth" \
"loopnz LOOP_AGAIN" \
modify [edx] \
parm [edi] [esi] [ebx] [eax] [ecx];
#pragma aux dr_ParallaxLine = \
"push ebp" \
"mov ebp,s_PagedWidth" \
"LOOP_AGAIN:" \
"xor eax,eax" \
"lodsb" \
"mov dl,[ebx+eax]" \
"mov [edi],dl" \
"add edi,ebp" \
"loopnz LOOP_AGAIN" \
"pop ebp" \
modify [eax] \
parm [edi] [esi] [ebx] [ecx];
#pragma aux dr_BlankVLine = \
"LOOP_AGAIN:" \
"mov [edi],al" \
"add edi,esi" \
"loopnz LOOP_AGAIN" \
parm [edi] [ecx] [esi] [al];
// Increment the Y coordinates.
curTopY = (pWall->topSlope * (Fixed)xLeft) + FIX(pWall->yTopIntercept);
curBottomY = (pWall->bottomSlope * (Fixed)xLeft) + FIX(pWall->yBottomIntercept);
if( pWall->viewSide == RightSide )
{
pTexture = tx_GetTexture( pWall->pLine->idRightTex );
tLeft = FIX(xLeft - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
tRight = FIX(xRight - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
}
else
{
pTexture = tx_GetTexture( pWall->pLine->idLeftTex );
tLeft = FIX(xRight - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
tRight = FIX(xLeft - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
}
worldXStart = pWall->x1 + FMul(tLeft, pWall->x2 - pWall->x1);
worldZStart = pWall->y1 + FMul(tLeft, pWall->y2 - pWall->y1);
worldXEnd = pWall->x1 + FMul(tRight, pWall->x2 - pWall->x1);
worldZEnd = pWall->y1 + FMul(tRight, pWall->y2 - pWall->y1);
worldXStep = (worldXEnd - worldXStart) / (xRight-xLeft);
worldZStep = (worldZEnd - worldZStart) / (xRight-xLeft);
fixedWorldX = worldXStart;
fixedWorldZ = worldZStart;
// Set up texture mapping stuff for this Wall (if it's not already.)
if( !pWall->bTextureInitted )
{
pWall->Px = pWall->originX;
pWall->Py = bottomY;
pWall->Pz = pWall->originZ / xWorldScale;
pWall->Mx = (pWall->horzX - pWall->originX);
pWall->My = 0;
pWall->Mz = (pWall->horzZ - pWall->originZ) / xWorldScale;
pWall->Nx = 0;
pWall->Ny = topY - bottomY;
pWall->Nz = 0;
// Magic numbers..
pWall->Oa = -FMul(pWall->Ny,pWall->Px);
pWall->Ha = FMul(pWall->Ny,pWall->Pz);
pWall->Oc = -FMul(pWall->Mx,pWall->Ny);
pWall->Hc = FMul(pWall->Mz,pWall->Ny);
pWall->bTextureInitted = TRUE;
}
// Set up the texture mapping.
a = pWall->Oa + ((xLeft-centerX) * pWall->Ha);
c = pWall->Oc + ((xLeft-centerX) * pWall->Hc);
// Get a pointer to the sky texture.
pSky = tx_GetTexture( curLevel.idCurSky );
// Draw from xLeft to xRight.
for( x=xLeft; x < xRight; x++ )
{
worldX = UNFIX(fixedWorldX);
worldZ = UNFIX(fixedWorldZ);
fixedWorldX += worldXStep;
fixedWorldZ += worldZStep;
// Get the texture position.
a += pWall->Ha;
c += pWall->Hc;
u = FDiv(a,c);
xTexturePos = (u >> pTexture->xTextureShift) & pTexture->xTextureMask;
// Get the right palette map.
if( bBlackAndWhite )
{
pPaletteMap = blackWhitePal;
}
else
{
paletteMap = (worldZ * worldZ) >> (FIXED_SHIFT-5);
#ifndef PALETTE_MAPS
paletteMap = (FIX(paletteMap) / zFadeOut) >> (FIXED_SHIFT-5);
#else
paletteMap = (FIX(paletteMap) / zFadeOut) >> (FIXED_SHIFT-6);
#endif
if( paletteMap >= nPaletteMaps )
paletteMap = nPaletteMaps-1;
pPaletteMap = pPaletteMaps[paletteMap];
}
// Do the actual drawing of the vertical lines.
unfixedTopY = UNFIX(curTopY);
unfixedBottomY = UNFIX(curBottomY);
textureStep = FDiv(FIX(pTexture->height-1)<<TEXTURE_FIX, (curBottomY - curTopY));
if( unfixedTopY > s_MinY )
{
// Draw the parallaxing sky.
pParallax = pSky->pVertLines[ (parallaxLookup.Get(x-s_MinX) + player.facingAngle) & pSky->xTextureMask ];
tempStep = textureStep;
textureStep = (FIX(128)<<TEXTURE_FIX) / (centerY - s_MinY);
texturePos = 0;
dr_WallLine( &pScreenMem[(s_MinY*s_PagedWidth) + s_PageLookup[x]], pParallax, pPaletteMaps[parallaxMap], s_MinX, unfixedTopY );
textureStep = tempStep;
// Do the texture map.
textureClipAdd = textureStep * unfixedTopY;
textureClipAdd -= FMul(textureStep, curTopY - FIXED_ONE);
texturePos = textureClipAdd;
if( unfixedBottomY >= s_MaxY )
dr_WallLine( &pScreenMem[(unfixedTopY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, s_MaxY-unfixedTopY );
else
dr_WallLine( &pScreenMem[(unfixedTopY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, unfixedBottomY-unfixedTopY );
}
else
{
textureClipAdd = FMul(textureStep, FIX(s_MinY)-curTopY + FIXED_ONE);
texturePos = textureClipAdd;
if( unfixedBottomY >= s_MaxY )
dr_WallLine( &pScreenMem[(s_MinY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, s_DrawHeight );
else
dr_WallLine( &pScreenMem[(s_MinY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, unfixedBottomY );
}
if( unfixedBottomY < s_MaxY )
dr_BlankVLine( &pScreenMem[((DWORD)unfixedBottomY*s_PagedWidth)+s_PageLookup[x]], s_Height-unfixedBottomY, s_PagedWidth, 0 );
// Increment top and bottom lines.
curTopY += pWall->topSlope;
curBottomY += pWall->bottomSlope;
}
if( bDisplayProjectionPoints )
{
if( pWall->viewSide == LeftSide )
{
// Left side has lines going up and down.
y1 = W_UNFIX(pWall->screenX1 * pWall->topSlope) + pWall->yTopIntercept;
y2 = W_UNFIX(pWall->screenX1 * pWall->bottomSlope) + pWall->yBottomIntercept;
dr_DrawLine( pWall->screenX1, y1, pWall->screenX1, y2, s_MaxX, s_MaxY, color1 );
y1 = W_UNFIX(pWall->screenX2 * pWall->topSlope) + pWall->yTopIntercept;
y2 = W_UNFIX(pWall->screenX2 * pWall->bottomSlope) + pWall->yBottomIntercept;
dr_DrawLine( pWall->screenX2, y1, pWall->screenX2, y2, s_MaxX, s_MaxY, color1 );
}
else
{
// Right side has lines going left to right.
y1 = W_UNFIX(pWall->screenX1 * pWall->topSlope) + pWall->yTopIntercept;
y2 = W_UNFIX(pWall->screenX2 * pWall->topSlope) + pWall->yTopIntercept;
dr_DrawLine( pWall->screenX1, y1, pWall->screenX2, y2, s_MaxX, s_MaxY, color2 );
y1 = W_UNFIX(pWall->screenX1 * pWall->bottomSlope) + pWall->yBottomIntercept;
y2 = W_UNFIX(pWall->screenX2 * pWall->bottomSlope) + pWall->yBottomIntercept;
dr_DrawLine( pWall->screenX1, y1, pWall->screenX2, y2, s_MaxX, s_MaxY, color2 );
}
}
}
/*
void dr_WallLine( BYTE *pDrawTo, BYTE *pBuffer, BYTE *pPaletteMap, Fixed bufferStartPos, Fixed bufferAdd, WORD vLineInc, WORD numPixels )
{
WORD i;
Fixed bufferPos;
BYTE color;
bufferPos=bufferStartPos;
for( i=0; i < numPixels; i++ )
{
color = pBuffer[bufferPos >> (FIXED_SHIFT+TEXTURE_FIX)];
*pDrawTo = pPaletteMap[color];
bufferPos += bufferAdd;
pDrawTo += vLineInc;
}
}
*/
/*
void dr_ParallaxLine( BYTE *pDrawTo, BYTE *pBuffer, BYTE *pPaletteMap, DWORD vLineInc, DWORD numPixels )
{
WORD i;
for( i=0; i < numPixels; i++ )
{
*pDrawTo = pPaletteMap[*pBuffer];
++pBuffer;
pDrawTo += vLineInc;
}
}
*/
void Draw2DEnvironment( CLineArray *pLines, CPointArray *pPoints, WORD xOffset, WORD yOffset, Fixed scale, WORD maxX, WORD maxY )
{
Fixed x1, y1, x2, y2;
Fixed x, y;
WORD drawX, drawY;
WORD i;
CLine *pCurLine;
CPoint *pCurPt;
// Draw all the Lines.
for( i=0; i < pLines->NumElements(); i++ )
{
pCurLine = pLines->GetLine(i);
x1 = xOffset + pCurLine->pPoint1->localX;
y1 = yOffset + pCurLine->pPoint1->localY;
x2 = xOffset + pCurLine->pPoint2->localX;
y2 = yOffset + pCurLine->pPoint2->localY;
x1 = x1 * scale;
y1 = y1 * scale;
x2 = x2 * scale;
y2 = y2 * scale;
dr_DrawLine( W_UNFIX(x1), -W_UNFIX(y1), W_UNFIX(x2), -W_UNFIX(y2), maxX, maxY, 30 );
}
// Draw all the Points.
for( i=0; i < pPoints->NumElements(); i++ )
{
pCurPt = pPoints->GetPoint(i);
x = xOffset + pCurPt->localX;
y = yOffset + pCurPt->localY;
x = x * scale;
y = y * scale;
drawX = W_UNFIX(x);
drawY = -W_UNFIX(y);
if( drawX >= 0 && drawX < maxX && drawY >= 0 && drawY < maxY )
pScreenMem[ (drawY*s_PagedWidth) + s_PageLookup[drawX] ] = 60;
}
s_SetPixel( W_UNFIX(player.xPos*scale), W_UNFIX(player.yPos*scale), 120 );
}
void dr_DrawLine( DWORD x1, DWORD y1, DWORD x2, DWORD y2, WORD maxX, WORD maxY, BYTE color )
{
WORD numPixels;
WORD i;
Fixed curX, curY, xInc, yInc;
WORD x, y;
// Test if it's off the screen so we might not have to draw it.
if( (x1 < 0 || x1 >= maxX) && (y1 < 0 || y1 >= maxY) &&
(x2 < 0 || x2 >= maxX) && (y2 < 0 || y2 >= maxY) )
return;
if( ABS(x2-x1) > ABS(y2-y1) )
numPixels = (WORD)ABS(x2-x1);
else
numPixels = (WORD)ABS(y2-y1);
if( numPixels < 2 )
return;
curX = FIX(x1);
curY = FIX(y1);
xInc = FIX(x2-x1) / numPixels;
yInc = FIX(y2-y1) / numPixels;
for( i=0; i < numPixels; i++ )
{
x = W_UNFIX(curX);
y = W_UNFIX(curY);
if( x >= 0 && x < maxX && y >= 0 && y < maxY )
pScreenMem[ s_PageLookup[x] + (y*s_PagedWidth) ] = color;
curX += xInc;
curY += yInc;
}
}
WORD dr_ClipAgainstLine( Fixed clipLine, Fixed *pX1, Fixed *pY1, Fixed *pX2, Fixed *pY2, Fixed *pT1, Fixed *pT2, BOOL bPositiveHalf )
{
assert( *pY1 != *pY2 );
// Replace (x1,y1) or (x2,y2), depending on which one was off the screen.
if( bPositiveHalf )
{
if( *pY1 < clipLine )
{
*pT1 = FDiv( clipLine - *pY1, *pY2 - *pY1 );
*pT2 = FIXED_ONE;
*pX1 = *pX1 + FMul(*pT1, *pX2 - *pX1);
*pY1 = *pY1 + FMul(*pT1, *pY2 - *pY1);
return 1;
}
else
{
*pT1 = 0;
*pT2 = FDiv( clipLine - *pY1, *pY2 - *pY1 );
*pX2 = *pX1 + FMul(*pT2, *pX2 - *pX1);
*pY2 = *pY1 + FMul(*pT2, *pY2 - *pY1);
return 2;
}
}
else
{
if( *pY1 < clipLine )
{
*pT1 = 0;
*pT2 = FDiv( clipLine - *pY1, *pY2 - *pY1 );
*pX2 = *pX1 + FMul(*pT2, *pX2 - *pX1);
*pY2 = *pY1 + FMul(*pT2, *pY2 - *pY1);
return 2;
}
else
{
*pT1 = FDiv( *pY1 - clipLine, *pY2 - *pY1 );
*pT2 = FIXED_ONE;
*pX1 = *pX1 - FMul(*pT1, *pX2 - *pX1);
*pY1 = *pY1 - FMul(*pT1, *pY2 - *pY1);
return 1;
}
}
return 0;
}